package com.tbit.uqbike.client.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.tbit.common.exceptions.ExternalException;
import com.tbit.uqbike.client.constant.WeixinConstant;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.util.http.HttpClientConnectionManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Value;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.*;

@Slf4j
public class GetWxOrderno {
//    private final static Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

    /**
     * 获取client实例
     */
    private static synchronized DefaultHttpClient getClient() {
        DefaultHttpClient client = new DefaultHttpClient();
        client = (DefaultHttpClient) HttpClientConnectionManager.getSSLInstance(client);

        return client;
    }

    /**
     * description:获取预支付id
     *
     * @param url
     * @param xmlParam
     * @return
     * @author ex_yangxiaoyi
     * @see
     */
    @SuppressWarnings("unchecked")
    public static String getPayNo(String url, String xmlParam, String brandName) {
        DefaultHttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
        HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
        String prepay_id = "";
        try {
            httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
            HttpResponse response = getClient().execute(httpost);
            String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
            log.info("请求预支付微信返回json串为{}",jsonStr);
            Map map = doXMLParse(jsonStr);
            log.info("解析的微信请求预支付返回结果为{}",JSON.toJSONString(map));
            // 微信创建订单返回报错
            // 	- 微信
            //		- <return_code><![CDATA[FAIL]]></return_code>
            //			- 错误信息的获取 ： return_msg 字段
            //		- <return_code><![CDATA[SUCCESS]]></return_code> 但是 <result_code><![CDATA[FAIL]]></result_code>
            //			- 错误信息的获取 ： err_code_des 字段
            //      - 字段通过map获取
            String returnCode = (String) map.getOrDefault("return_code","");
            String resultCode = (String) map.getOrDefault("result_code","");
            if (Objects.equals(returnCode,"FAIL")) {
                String externalExceptionMsg = (String) map.get("return_msg");
                throw new ExternalException("创建订单失败：商户异常",externalExceptionMsg,brandName);
            }else if(Objects.equals(resultCode,"FAIL")){
                String externalExceptionMsg = (String) map.get("err_code_des");
                throw new ExternalException("创建订单失败：商户异常",externalExceptionMsg,brandName);
            }
            prepay_id = (String) map.get("prepay_id");
        }
        catch (ExternalException e){
            log.error("获取微信预支付id失败",e);
            throw e;
        }
        catch (Exception e) {
            log.error("微信调用成功，本地解析失败",e);
        }
        return prepay_id;
    }

    /**
     * 退款接口
     *
     * @param url
     * @param
     */
    public static Boolean return_deposit(String accountId, Integer type, String url, String xml, String parner) {
        Map<Object, Object> map = new HashMap<>();
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");

	    	 /*String certPath=String.format(WeixinConstant.deposit_return_app_path, accountId);
	    	 if(type==2){
	    		 certPath=String.format(WeixinConstant.deposit_return_weixin_path, accountId);
	    	 }*/
            String certPath = String.format(WeixinConstant.deposit_return_app_path, accountId);
            File file = new File(String.format(WeixinConstant.deposit_return_weixin_path, parner));
            if (file.exists()) {
                certPath = String.format(WeixinConstant.deposit_return_weixin_path, parner);
            } else {
                // String certPath=String.format(WeixinConstant.deposit_return_app_path, accountId);
                if (type == 2) {
                    certPath = String.format(WeixinConstant.deposit_return_weixin_path, accountId);
                }
            }

            FileInputStream instream = new FileInputStream(new File(certPath));
            try {
                keyStore.load(instream, parner.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, parner.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

            HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
            httpost.setEntity(new StringEntity(xml, "UTF-8"));
            HttpResponse weixinResponse = httpClient.execute(httpost);
            String jsonStr = EntityUtils.toString(weixinResponse.getEntity(), "UTF-8");
            log.info("微信返回的字符串" + jsonStr);
            map = GetWxOrderno.doXMLParse(jsonStr);
            log.info("\n" + "微信返回的字符串" + jsonStr + "map.get(\"result_code\")=" + map.get("result_code"));
        } catch (Exception e) {
            log.error("退款异常", e);
            return false;
        }
        if ("success".equalsIgnoreCase((String) map.get("result_code"))) {
            log.info("退款成功");
            return true;
        } else {
            log.warn("退款失败=" + map.get("err_code_des"));
            throw new BaseException(map.get("err_code_des").toString(), map.get("err_code_des").toString());
        }
    }

    /**
     * description:获取扫码支付连接
     *
     * @param url
     * @param xmlParam
     * @return
     * @author ex_yangxiaoyi
     * @see
     */
    @SuppressWarnings("unchecked")
    public static String getCodeUrl(String url, String xmlParam) {
        DefaultHttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
        HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
        String code_url = "";
        try {
            httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
            HttpResponse response = getClient().execute(httpost);
            String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
            if (jsonStr.indexOf("FAIL") != -1) {
                return code_url;
            }
            Map map = doXMLParse(jsonStr);
            code_url = (String) map.get("code_url");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return code_url;
    }

    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
     *
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Map doXMLParse(String strxml) throws Exception {
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        Map m = new HashMap();
        InputStream in = String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }

            m.put(k, v);
        }

        // 关闭流
        in.close();

        return m;
    }

    /**
     * 获取子结点的xml
     *
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }

    public static void main(String[] args) {
        String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wx73d9c3244b6d6d98]]></appid><mch_id><![CDATA[1480293312]]></mch_id>"
                + "<nonce_str><![CDATA[OUJ8uTp0i7hTfjmu]]></nonce_str>"
                + "<sign><![CDATA[FFC6F0F1DBA4DEBA961A317513BF6E69]]></sign>"
                + "<result_code><![CDATA[FAIL]]></result_code>"
                + "<err_code><![CDATA[ERROR]]></err_code>"
                + "<err_code_des><![CDATA[订单已全额退款]]></err_code_des>"
                + "</xml>";

        try {
            Map map = GetWxOrderno.doXMLParse(result);
            System.out.println(map.get("result_code"));
            System.out.println(map.get("err_code"));
            System.out.println(map.get("err_code_des"));
        } catch (Exception e) {
            System.out.println("异常");
        }
    }

}